package pnca;

import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import javax.swing.JFileChooser;
import javax.swing.Timer;

/**
 * PNCAUI (Pacific Northwest Climate Analysis) is the initial user interface
 * which enables the user to select input files before executing the analysis.
 *
 * @author Niko Simonson
 * @author Brett Yasutake
 * @version 0.9.121 Release Candidate, 21st commit
 * @date 12/30/2013
 */
public class PNCAUI extends javax.swing.JFrame {
    
    // Input file selection variables
    protected JFileChooser fileSelector;    
    public String[] selectedFileNames;
    protected File[] selectedFiles;
    
    // User interface variables
    protected static StatusAdapter status;  // status adapter to report status messages
    String statusMessage;           // latest retreived status message from the
                                    // status adapter
    // Execution variables
    Thread analysisThread;          // thread for analytics module execution
    private ProvenanceAdapter pAdapter;   // provenance adapter to log exceptions
    boolean initialized;            // true if MASS has been initialized
    boolean isRunning;              // true if analysis is currently running
    private Timer timer;            // run-time performance measurement

    /**
     * PNCAUI Creates new a new PNCAUI form.
     */
    public PNCAUI() {
        
        fileSelector = new JFileChooser();
        fileSelector.setMultiSelectionEnabled(true);
        initComponents();

        pAdapter = new ProvenanceAdapter();

        status = new StatusAdapter();

        // Set up analytics selection list
        File analyticsFolder = new File(Constants.ANALYTICSFOLDER);
        String[] analyticsClasses = analyticsFolder.list();
        for( int i = 0; i < analyticsClasses.length; i++) {        
            algorithmCBox.addItem(analyticsClasses[i].substring(0, analyticsClasses[i].length()-5));
        }
        // Timer used to periodically check for status messages
        timer = new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                timerActionPerformed(evt);
            }
        });
        isRunning = false;
        initialized = false;
    }
    
    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jButton2 = new javax.swing.JButton();
        titleLabel = new javax.swing.JLabel();
        closeButton = new javax.swing.JButton();
        configureInputButton = new javax.swing.JButton();
        panoplyButton = new javax.swing.JButton();
        algorithmCBox = new javax.swing.JComboBox();
        runButton = new javax.swing.JButton();
        statusLbl = new javax.swing.JLabel();
        statusMessageLabel = new javax.swing.JLabel();
        algorithmLbl = new javax.swing.JLabel();
        imageJlabel = new javax.swing.JLabel();

        jButton2.setText("jButton1");

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setMinimumSize(new java.awt.Dimension(660, 345));
        setResizable(false);

        titleLabel.setFont(new java.awt.Font("Dialog", 1, 24)); // NOI18N
        titleLabel.setText("Pacific Northwest Climate Analysis");

        closeButton.setText("Close");
        closeButton.setToolTipText("");
        closeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                closeButtonActionPerformed(evt);
            }
        });

        configureInputButton.setText("Configure Input");
        configureInputButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                configureInputButtonActionPerformed(evt);
            }
        });

        panoplyButton.setText("Open Panoply Results Viewer");
        panoplyButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                panoplyButtonActionPerformed(evt);
            }
        });

        algorithmCBox.setMaximumRowCount(15);
        algorithmCBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                algorithmCBoxActionPerformed(evt);
            }
        });

        runButton.setText("Start Analysis");
        runButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                runButtonActionPerformed(evt);
            }
        });

        statusLbl.setText("Current Status:");

        statusMessageLabel.setText("Setting Up");

        algorithmLbl.setText("Select Analytics Module:");

        imageJlabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pnca/frost days 50 years.png"))); // NOI18N
        imageJlabel.setText("imageJlabel");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(runButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(panoplyButton)
                        .addGap(76, 76, 76)
                        .addComponent(closeButton)
                        .addGap(31, 31, 31))
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                            .addComponent(titleLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addGroup(layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                                        .addComponent(algorithmCBox, javax.swing.GroupLayout.PREFERRED_SIZE, 234, javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED))
                                    .addGroup(layout.createSequentialGroup()
                                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                            .addComponent(algorithmLbl, javax.swing.GroupLayout.PREFERRED_SIZE, 191, javax.swing.GroupLayout.PREFERRED_SIZE)
                                            .addComponent(configureInputButton))
                                        .addGap(61, 61, 61)))
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addGroup(layout.createSequentialGroup()
                                        .addComponent(imageJlabel, javax.swing.GroupLayout.PREFERRED_SIZE, 240, javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addGap(58, 84, Short.MAX_VALUE))
                                    .addGroup(layout.createSequentialGroup()
                                        .addComponent(statusLbl)
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                        .addComponent(statusMessageLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))
                        .addContainerGap(72, Short.MAX_VALUE))))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(titleLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 38, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(imageJlabel, javax.swing.GroupLayout.DEFAULT_SIZE, 150, Short.MAX_VALUE)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(45, 45, 45)
                        .addComponent(configureInputButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(algorithmLbl, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(statusLbl)
                    .addComponent(statusMessageLabel)
                    .addComponent(algorithmCBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(34, 34, 34)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(runButton)
                    .addComponent(closeButton)
                    .addComponent(panoplyButton))
                .addGap(20, 20, 20))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    /**
     * Exits the pac-nw-climate-analysis application
     * 
     * @param evt   the action event when button is pressed
     */
    private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed
        // Close button, exit the application
        System.exit(0);
    }//GEN-LAST:event_closeButtonActionPerformed

    /**
     * Opens a file chooser for the user to select the input NetCDF files.
     * 
     * @param evt   the action event when button is pressed
     */
    private void configureInputButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_configureInputButtonActionPerformed
        // Configure input files button, present user with file selection
        // dialog, capture selected file names in array
        try {
            // Open file selector
            int result = fileSelector.showOpenDialog(this);

            // Retrieve selected input files
            if (result == JFileChooser.APPROVE_OPTION) {
                selectedFiles = fileSelector.getSelectedFiles();
            }
            try {
                if (selectedFiles != null) {
                    // Retreive filepaths from selected files and store in an array
                    selectedFileNames = new String[selectedFiles.length];
                    for (int i = 0; i < selectedFiles.length; ++i) {
                        selectedFileNames[i] = selectedFiles[i].getCanonicalPath();
                    }
                } else {
                    selectedFiles = null;
                    selectedFileNames = null;
                }
            } catch (IOException ioe) {
                pAdapter.log(Level.SEVERE, "exception caught in PNCAUI", ioe);
            } catch (Exception e) {
                pAdapter.log(Level.SEVERE, "exception caught in PNCAUI", e);
            }
        } catch (Exception e) {
            pAdapter.log(Level.SEVERE, "outer block", e);
        }
    }//GEN-LAST:event_configureInputButtonActionPerformed

    /**
     * Launches Panoply application on the operating system.
     * 
     * @param evt   the action event when button is pressed
     */
    private void panoplyButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_panoplyButtonActionPerformed
        try {

            analysisThread = new Thread() {
                    public void run() {
                        try {
                            String[] cmd = new String[3];        
                            cmd[0] = "java";
                            cmd[1] = "-jar";
                            cmd[2] = Constants.PANOPLYJARPATH;
                            
                            Process proc = Runtime.getRuntime().exec(cmd);

                            int exitValue = proc.waitFor();
                        } catch (Exception ex) {
                            pAdapter.log(Level.SEVERE, "exception caught while launching Panoply", ex);
                        }
                    }
                };
                analysisThread.start();
        } catch (Exception ex) {
            pAdapter.log(Level.SEVERE, "exception caught in PNCAUI", ex);
        }
    }//GEN-LAST:event_panoplyButtonActionPerformed

    /**
     * The algorithm selection combination box does not have any actions.
     * 
     * @param evt the action event when button is pressed 
     */
    private void algorithmCBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_algorithmCBoxActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_algorithmCBoxActionPerformed

    /**
     * The run button initiates the analysis execution. A new thread is created
     * to execute the selected analytics module on the selected input files.
     * 
     * @param evt   the action event when the button is pressed
     */
    private void runButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_runButtonActionPerformed
        // Perform analysis button, execute analytics module in its own thread,
        // report status message updates
        timer.start();
        if (analysisThread != null && !analysisThread.isAlive()) {
            isRunning = false;
        }

        if (!isRunning) {
            if (algorithmCBox.getSelectedItem() != null) {
                final String selectedAnalysis = algorithmCBox.getSelectedItem().toString();
                analysisThread = new Thread() {
                    public void run() {
                        try {
                            // Perform analysis
                            ExecutionAdapter.runAnalysis(selectedAnalysis, status, selectedFileNames, initialized);
//                            initialized = true;

                        } catch (Exception ex) {
                           // pAdapter.log(Level.SEVERE, "exception caught in PNCAUI", ex);
                        }
                    }
                };
                analysisThread.start();
                isRunning = true;
//                algorithmCBox.setEnabled(false);
            }
        }
    }//GEN-LAST:event_runButtonActionPerformed

    /**
     * Check for new status messages every one second.
     * 
     * @param evt   the timer event that goes off every one second
     */
    private void timerActionPerformed(java.awt.event.ActionEvent evt) {
        // Retreive latest message from status adapter
        statusMessage = status.getCurrentMessage();

        // Do not update UI if status has not changed since last check
        if (!statusMessage.equals(statusMessageLabel.getText())) {
            statusMessageLabel.setText(statusMessage);
        }
    }

    /**
     * The main function instantiates a new PNCAUI.
     * 
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(PNCAUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(PNCAUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(PNCAUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(PNCAUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new PNCAUI().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JComboBox algorithmCBox;
    private javax.swing.JLabel algorithmLbl;
    private javax.swing.JButton closeButton;
    private javax.swing.JButton configureInputButton;
    private javax.swing.JLabel imageJlabel;
    private javax.swing.JButton jButton2;
    private javax.swing.JButton panoplyButton;
    private javax.swing.JButton runButton;
    private javax.swing.JLabel statusLbl;
    private javax.swing.JLabel statusMessageLabel;
    private javax.swing.JLabel titleLabel;
    // End of variables declaration//GEN-END:variables
}
